﻿using System;
using System.Threading;
using System.Windows.Forms;
using EmbeddedSharp.Core;
using WeifenLuo.WinFormsUI.Docking;
using Zove.Scripting.Core;
using System.ComponentModel;
using EmbeddedSharp.Scripting;
using System.IO;
using System.Collections.Generic;

namespace Zove.Desktop {
    public class ProgrammingEditor : EditingForm, IDebuggableView, ICancellable {

        public override string GetFileFilter() {
            return "Programming files (*.fpz) | *.fpz";
        }

        public List<BreakPoint> BreakPoints {
            get {
                return DesktopFormContext.Context.BreakPoints;
            }
        }

        public void Print() {

        }

        public override string GetFileExtension() {
            return ".fpz";
        }

        public ProgrammingEditor()
            : base() {
            Init();
        }

        public void Init() {

        }

        public ProgrammingEditor(string fileName)
            : base(fileName) {
            Init();
        }

        private ConsoleStreamWriter writer
            = new ConsoleStreamWriter();

        public DebuggingState State {
            get {
                if (script == null) {
                    return DebuggingState.Idle;
                }

                return script.State;
            }
        }

        private BackgroundWorker backgroundWorker = null;

        public override void Run() {
            if (script != null) {
                if (script.State == DebuggingState.Running || script.State == DebuggingState.Breaked) {
                    script.Stop();
                }

                script.Dispose();
                script = null;
            }

            Console.SetOut(writer);
            script = new ZoveScriptingObject(this.teSource.Text);

            script.Breaked
                += new EventHandler<DebuggingEventArgs>(
                    virtualMachine_Breaked);
            script.Stopped
                += new EventHandler<DebuggingEventArgs>(
                    virtualMachine_Stopped);

            script.Run();
            ShowConsoleWindow();
        }

        public virtual void StepInto() {
        
        }

        public virtual void StepOver() {
        
        }

        #region back ground worker
        public void backgroundWorker_DoWork(
            object sender, DoWorkEventArgs args) {
            if (script == null || script.State == DebuggingState.Stopped) {
                if (script != null) {
                    script.Dispose();
                    script = null;
                }

                Console.SetOut(writer);

                // the virutal machine is not started before
                string source = args.Argument as string;
                script = new ZoveScriptingObject(source);
                foreach (BreakPoint bp in DesktopFormContext.Context.BreakPoints) {
                    if (string.Compare(base.FileName, bp.File, true) == 0) {
                        script.BreakPoints.Add(bp);
                    }
                }

                script.Breaked
                    += new EventHandler<DebuggingEventArgs>(
                        virtualMachine_Breaked);
                script.Stopped
                    += new EventHandler<DebuggingEventArgs>(
                        virtualMachine_Stopped);

                script.StartDebugging();
            } else {
                script.Resume();
            }
        }

        #region debugger calls
        public virtual void Break() {
            throw new NotImplementedException();
        }

        public virtual void Stop() {
            throw new NotImplementedException();
        }

        public virtual void Resume() {
            StartDebugging();
        }

        public virtual void Restart() {
            throw new NotImplementedException();
        }

        public virtual double Profile() {
            throw new NotImplementedException();
        }
        #endregion

        public void backgroundWorker_RunWorkerCompleted(
            object sender, RunWorkerCompletedEventArgs args) {
            this.ShowConsoleWindow();
        }

        public virtual void Cancel() {
            if (backgroundWorker != null) {
                backgroundWorker.CancelAsync();
                while (backgroundWorker.CancellationPending) {
                    Thread.Sleep(1000);
                }
                MessageBox.Show("The evaluation was terminated.");
                //this.ShowConsoleWindow();
            }
        }
        #endregion

        /// <summary>
        /// Showing results
        /// </summary>
        public void ShowConsoleWindow() {
            ConsoleWindow cw = new ConsoleWindow(
                writer.Stream.ToString());

            // writer.Stream.ToString()
            cw.MdiParent = this.MdiParent;
            cw.Show(this.DockPanel);
            cw.DockState = DockState.DockBottom;
        }

        /// <summary>
        /// Get the colorized scheme
        /// </summary>
        /// <returns></returns>
        public override string GetColourScheme() {
            return "C#";
        }

        private ZoveScriptingObject script = null;

        public IContext Context {
            get {
                return script.Context;
            }
        }

        private string source = string.Empty;

        public void virtualMachine_Breaked(object sender, DebuggingEventArgs e) {
            DesktopFormContext.Context.Main.SwitchDebuggingMode(
                DebuggingState.Breaked);
        }

        public void virtualMachine_Stopped(object sender, DebuggingEventArgs e) {
            DesktopFormContext.Context.Main.SwitchDebuggingMode(
                DebuggingState.Stopped);
        }

        public void StartDebugging() {
            if (backgroundWorker != null && backgroundWorker.IsBusy) {
                if (MessageBox.Show(
                    "Another computation is in progress, do you want to stop it and proceed this one?", "",
                    MessageBoxButtons.OKCancel) == DialogResult.Cancel) {
                    return;
                }
                backgroundWorker.CancelAsync();
            }

            Console.SetOut(writer);
            DesktopFormContext.Context.Main.SwitchDebuggingMode(DebuggingState.Running);

            if (string.IsNullOrEmpty(teSource.Text)) {
                MessageBox.Show("Please put some code in the editing window to proceed.");
                return;
            }

            backgroundWorker = new BackgroundWorker();
            backgroundWorker.WorkerSupportsCancellation = true;
            backgroundWorker.RunWorkerCompleted
                += new RunWorkerCompletedEventHandler(
                    backgroundWorker_RunWorkerCompleted);
            backgroundWorker.DoWork
                += new DoWorkEventHandler(
                    backgroundWorker_DoWork);

            backgroundWorker.RunWorkerAsync(this.teSource.Text);
        }
    }
}
